#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>

#define PORT 7001
#define BUFFER_SIZE 8192
#define MAX_HEADER_SIZE 4096
#define BASE_DIR "./received_files"
#define ZIP_DIR BASE_DIR "/extracted_zips"
#define LIB_DIR BASE_DIR "/libraries"

// 创建目录
void create_directories() {
    mkdir(BASE_DIR, 0755);
    mkdir(ZIP_DIR, 0755);
    mkdir(LIB_DIR, 0755);
}

// 解码 URL 编码
void url_decode(char *str) {
    char *p = str;
    char decoded[BUFFER_SIZE];
    int i = 0;
    
    while (*p) {
        if (*p == '%' && *(p+1) && *(p+2)) {
            char hex[3] = {*(p+1), *(p+2), 0};
            decoded[i++] = (char)strtol(hex, NULL, 16);
            p += 3;
        } else if (*p == '+') {
            decoded[i++] = ' ';
            p++;
        } else {
            decoded[i++] = *p++;
        }
    }
    decoded[i] = '\0';
    strcpy(str, decoded);
}

// 获取当前时间字符串
char* get_timestamp() {
    static char timestamp[64];
    time_t now = time(NULL);
    struct tm *t = localtime(&now);
    strftime(timestamp, sizeof(timestamp), "%Y%m%d_%H%M%S", t);
    return timestamp;
}

// 处理 ZIP 文件
void process_zip(const char *filepath, const char *filename) {
    char command[BUFFER_SIZE];
    char extract_dir[BUFFER_SIZE];
    
    snprintf(extract_dir, sizeof(extract_dir), "%s/%s_%s", 
             ZIP_DIR, filename, get_timestamp());
    
    mkdir(extract_dir, 0755);
    
    snprintf(command, sizeof(command), 
             "unzip -q '%s' -d '%s' && echo '解压成功: %s' || echo '解压失败: %s'", 
             filepath, extract_dir, filename, filename);
    
    system(command);
}

// 处理 SO 文件
void process_so(const char *filepath, const char *filename) {
    char dest_path[BUFFER_SIZE];
    char command[BUFFER_SIZE];
    
    snprintf(dest_path, sizeof(dest_path), "%s/%s_%s.so", 
             LIB_DIR, filename, get_timestamp());
    
    // 复制文件
    snprintf(command, sizeof(command), "cp '%s' '%s'", filepath, dest_path);
    system(command);
    
    // 设置权限
    snprintf(command, sizeof(command), "chmod 755 '%s'", dest_path);
    system(command);
    
    // 获取文件信息
    snprintf(command, sizeof(command), "file '%s'", dest_path);
    system(command);
}

// 检测文件类型并处理
void process_file(const char *filepath, const char *filename) {
    char command[BUFFER_SIZE];
    char result[BUFFER_SIZE];
    FILE *fp;
    
    // 使用 file 命令检测文件类型
    snprintf(command, sizeof(command), "file -b '%s'", filepath);
    fp = popen(command, "r");
    if (fp == NULL) return;
    
    if (fgets(result, sizeof(result), fp) != NULL) {
        // 去除换行符
        result[strcspn(result, "\n")] = 0;
        
        printf("检测到文件类型: %s\n", result);
        
        if (strstr(result, "Zip archive") != NULL) {
            printf("处理 ZIP 文件: %s\n", filename);
            process_zip(filepath, filename);
        } else if (strstr(result, "ELF") != NULL && strstr(result, "shared object") != NULL) {
            printf("处理 SO 文件: %s\n", filename);
            process_so(filepath, filename);
        } else {
            printf("无需特殊处理的文件: %s\n", filename);
        }
    }
    
    pclose(fp);
}

// 解析 multipart 表单数据
int parse_multipart(const char *data, size_t data_len, const char *boundary, 
                   char *filename, size_t filename_len, char **file_start, size_t *file_len) {
    char boundary_full[256];
    snprintf(boundary_full, sizeof(boundary_full), "--%s", boundary);
    
    // 查找边界
    char *boundary_pos = strstr(data, boundary_full);
    if (!boundary_pos) return -1;
    
    // 查找文件名
    char *filename_pos = strstr(boundary_pos, "filename=\"");
    if (filename_pos) {
        filename_pos += 10; // 跳过 filename="
        char *filename_end = strchr(filename_pos, '"');
        if (filename_end) {
            size_t len = filename_end - filename_pos;
            if (len < filename_len) {
                strncpy(filename, filename_pos, len);
                filename[len] = '\0';
                url_decode(filename); // 解码 URL 编码的文件名
            }
        }
    }
    
    // 查找文件内容的开始位置
    char *content_start = strstr(boundary_pos, "\r\n\r\n");
    if (content_start) {
        content_start += 4; // 跳过 \r\n\r\n
        
        // 查找下一个边界作为文件内容结束
        char *next_boundary = strstr(content_start, boundary_full);
        if (next_boundary) {
            *file_start = content_start;
            *file_len = next_boundary - content_start;
            
            // 去除末尾的 \r\n
            while (*file_len > 0 && 
                   (*(*file_start + *file_len - 1) == '\n' || 
                    *(*file_start + *file_len - 1) == '\r')) {
                (*file_len)--;
            }
            
            return 0;
        }
    }
    
    return -1;
}

// 发送 HTTP 响应
void send_http_response(int client_sock, int status_code, const char *status_msg, 
                       const char *content_type, const char *body) {
    char header[BUFFER_SIZE];
    time_t now = time(NULL);
    struct tm *tm = gmtime(&now);
    char time_str[64];
    strftime(time_str, sizeof(time_str), "%a, %d %b %Y %H:%M:%S GMT", tm);
    
    snprintf(header, sizeof(header),
             "HTTP/1.1 %d %s\r\n"
             "Server: C File Server\r\n"
             "Date: %s\r\n"
             "Content-Type: %s\r\n"
             "Content-Length: %zu\r\n"
             "Connection: close\r\n"
             "\r\n",
             status_code, status_msg, time_str, content_type, strlen(body));
    
    send(client_sock, header, strlen(header), 0);
    send(client_sock, body, strlen(body), 0);
}

// 生成 HTML 上传页面
char* generate_upload_page() {
    static char html[BUFFER_SIZE * 2];
    
    snprintf(html, sizeof(html),
             "<!DOCTYPE html>"
             "<html>"
             "<head>"
             "<title>文件上传</title>"
             "<meta charset=\"utf-8\">"
             "<style>"
             "body { font-family: Arial, sans-serif; margin: 40px; }"
             ".upload-form { border: 2px dashed #ccc; padding: 20px; text-align: center; }"
             "input, button { margin: 10px; padding: 10px; }"
             ".success { color: green; }"
             ".error { color: red; }"
             "</style>"
             "</head>"
             "<body>"
             "<h1>文件上传到服务器</h1>"
             "<div class=\"upload-form\">"
             "<form method=\"POST\" enctype=\"multipart/form-data\">"
             "<input type=\"file\" name=\"file\" required><br>"
             "<button type=\"submit\">上传文件</button>"
             "</form>"
             "</div>"
             "<p>支持的文件类型: .zip, .so</p>"
             "</body>"
             "</html>");
    
    return html;
}

int main() {
    int server_fd, client_fd;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    
    create_directories();
    
    // 创建 socket
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    
    // 设置 socket 选项
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);
    
    // 绑定端口
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    
    // 开始监听
    if (listen(server_fd, 10) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    
    printf("HTTP 文件服务器启动，监听端口 %d\n", PORT);
    printf("Web 访问地址: http://localhost:%d\n", PORT);
    printf("文件保存目录: %s\n", BASE_DIR);
    
    while (1) {
        printf("等待客户端连接...\n");
        
        // 接受连接
        if ((client_fd = accept(server_fd, (struct sockaddr *)&address, 
                               (socklen_t*)&addrlen)) < 0) {
            perror("accept");
            continue;
        }
        
        printf("客户端连接: %s:%d\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
        
        char buffer[BUFFER_SIZE * 2];
        ssize_t bytes_read;
        
        // 读取请求头
        bytes_read = recv(client_fd, buffer, sizeof(buffer) - 1, 0);
        if (bytes_read > 0) {
            buffer[bytes_read] = '\0';
            
            // 检查是否是 GET 请求
            if (strncmp(buffer, "GET", 3) == 0) {
                // 返回上传页面
                send_http_response(client_fd, 200, "OK", "text/html", generate_upload_page());
            }
            // 检查是否是 POST 请求
            else if (strncmp(buffer, "POST", 4) == 0) {
                // 查找 Content-Type 头
                char *content_type = strstr(buffer, "Content-Type:");
                if (content_type) {
                    char *boundary_start = strstr(content_type, "boundary=");
                    if (boundary_start) {
                        boundary_start += 9; // 跳过 boundary=
                        char boundary[100];
                        sscanf(boundary_start, "%99s", boundary);
                        
                        // 解析 multipart 数据
                        char filename[256] = "";
                        char *file_data = NULL;
                        size_t file_len = 0;
                        
                        if (parse_multipart(buffer, bytes_read, boundary, 
                                           filename, sizeof(filename), &file_data, &file_len) == 0) {
                            
                            if (strlen(filename) > 0 && file_data && file_len > 0) {
                                // 保存文件
                                char filepath[512];
                                snprintf(filepath, sizeof(filepath), "%s/%s", BASE_DIR, filename);
                                
                                FILE *file = fopen(filepath, "wb");
                                if (file) {
                                    fwrite(file_data, 1, file_len, file);
                                    fclose(file);
                                    
                                    printf("文件保存成功: %s (大小: %zu 字节)\n", filename, file_len);
                                    
                                    // 处理文件
                                    process_file(filepath, filename);
                                    
                                    char success_msg[512];
                                    snprintf(success_msg, sizeof(success_msg),
                                             "<html><body>"
                                             "<h1>上传成功</h1>"
                                             "<p>文件: %s</p>"
                                             "<p>大小: %zu 字节</p>"
                                             "<p><a href=\"/\">返回上传页面</a></p>"
                                             "</body></html>",
                                             filename, file_len);
                                    
                                    send_http_response(client_fd, 200, "OK", "text/html", success_msg);
                                } else {
                                    send_http_response(client_fd, 500, "Internal Server Error", 
                                                      "text/html", "<h1>保存文件失败</h1>");
                                }
                            } else {
                                send_http_response(client_fd, 400, "Bad Request", 
                                                  "text/html", "<h1>未找到文件数据</h1>");
                            }
                        } else {
                            send_http_response(client_fd, 400, "Bad Request", 
                                              "text/html", "<h1>解析表单数据失败</h1>");
                        }
                    } else {
                        send_http_response(client_fd, 400, "Bad Request", 
                                          "text/html", "<h1>无效的 Content-Type</h1>");
                    }
                } else {
                    send_http_response(client_fd, 400, "Bad Request", 
                                      "text/html", "<h1>缺少 Content-Type 头</h1>");
                }
            } else {
                send_http_response(client_fd, 405, "Method Not Allowed", 
                                  "text/html", "<h1>不支持的请求方法</h1>");
            }
        }
        
        close(client_fd);
    }
    
    close(server_fd);
    return 0;
}
